
# Copyright (c) 2014, Franklin Brauning V.  All rights reserved.
# 
#    El desarrollo inicial de esta utilidad fue producido
#    por Franklin Brauning <brauningbar@gmail.com>
# 
#    Si consideras que este codigo puede serte util, eres libre
#    de usarlo a conveniencia, pero no olvides mantener la licencia
#    y dar credito al autor.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 
#   * Redistributions of source code must retain the above copyright notice, this
#     list of conditions and the following disclaimer.
# 
#   * Redistributions in binary form must reproduce the above copyright notice,
#     this list of conditions and the following disclaimer in the documentation
#     and/or other materials provided with the distribution.
# 
#   * Neither the name of the author nor the names of its contributors may
#     be used to endorse or promote products derived from this software without
#     specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from django.db import models
from .base import *
import time, datetime
from .strings import *
from django.contrib.auth.models import User

def datetimenow():
	return datetime.datetime(*time.localtime()[:6])

def samedate(a, b):
	if not a or not b:
		return a == b
	return (a.year, a.month, a.day) == (b.year, b.month, b.day)

def formatdatetime(d):
	return d.strftime("%d/%m/%Y %H:%M")
def formatdate(d):
	return d.strftime("%d/%m/%Y")
def formattime(d):
	return d.strftime("%H:%M")


def show_tracked(func):
	''' composable __str__ decorator to show tracked models info in
	human way '''
	def w(self):
		m = ["modificado"]
		now = datetimenow()
		if self.muser:
			m.append("por " + str(self.muser))
		if samedate(self.mdatetime, now):
			m.append("a las " + formattime(self.mdatetime))
		elif self.mdatetime:
			m.append("en " + formatdatetime(self.mdatetime))

		c = ["creado"]
		if self.cuser:
			c.append("por " + str(self.cuser))
		if samedate(self.cdatetime, now):
			c.append("a las " + formattime(self.cdatetime))
		elif self.cdatetime:
			c.append("en " + formatdatetime(self.cdatetime))

		stamp = " ".join(m) + ", " + " ".join(c)
		s,ats = func(self)
		ats.append(stamp)
		return s,ats
	return w

def show_tracked_complete(func):
	''' composable __str__ decorator to show tracked models info in
	human way (verboser) '''
	def w(self):
		s,ats = func(self)
		if self.mdatetime and self.cdatetime:
			ats.append("por %s en %s, creado por %s en %s" % \
						(str(self.muser), formatdatetime(self.mdatetime),
						 str(self.cuser), formatdatetime(self.cdatetime)))
		return s,ats
	return w

def show_tracked_m(func):
	''' composable __str__ decorator to show tracked models
	modification info (modification time and user) '''
	def w(self):
		s,ats = func(self)
		if self.mdatetime:
			ats.append("por %s en %s" % (
			  str(self.muser), formatdatetime(self.mdatetime)))
		return s,ats
	return w

def show_tracked_c(func):
	''' composable __str__ decorator to show tracked models creation
	info (creation time and user) '''
	def w(self):
		s,ats = func(self)
		if self.cdatetime:
			ats.append("creado por %s en %s" % (
			  str(self.cuser), formatdatetime(self.cdatetime)))
		return s,ats
	return w

def show_tracked_mtime(func):
	''' composable __str__ decorator to show tracked models
	modification time '''
	def w(self):
		s,ats = func(self)
		if self.mdatetime:
			ats.append(formatdatetime(self.mdatetime))
		return s,ats
	return w


# FIXME
#
# En mis tests con mysql se produce este error proveniente de mysql, tanto para
# cuser como para muser
#
#django.db.utils.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`test_testdjango`.`configurador_categoria`, CONSTRAINT `cuser_id_refs_id_2c66949c` FOREIGN KEY (`cuser_id`) REFERENCES `auth_user` (`id`))')
#
# Para poder funcionar con mysql esos campos tienen deshabilitada la
# verificacion de 'tipos' sql
#
_FOREIGNKEY_KWARGS = {'db_constraint':False} if ISMYSQL else {}

class tracked(abstractmodel):
	''' enrich a model to log user and datetime of creation and
	modification events
	'''
	cdatetime = models.DateTimeField(editable=False,
	  verbose_name=strcdatetime)
	cuser = models.ForeignKey(User, related_name="+",
	  verbose_name=strcuser, null=True, editable=False, **_FOREIGNKEY_KWARGS)
	mdatetime = models.DateTimeField(editable=False,
	  verbose_name=strmdatetime)
	muser = models.ForeignKey(User, related_name="+",
	  verbose_name=strmuser, null=True, editable=False, **_FOREIGNKEY_KWARGS)
	class Meta:
		abstract = True

	def who(self, user):
		''' before .save the model has to be informed of the
		user responsable for the creation/modification.

		.save will fail if the model doesnt know the responsable user
		'''
		self._user = user

	def datetime(self, dt):
		''' force automatic datetime detecion with a provided datetime '''
		self._datetime = dt

	def copywho(self, oth):
		''' copy user and datetime data from another tracked object '''
		self.cuser = oth.cuser
		self.cdatetime = oth.cdatetime
		self.who(oth.muser)

	def save(self, *a, **kw):
		''' save model logging user and datetime of the
		creation/modification
		'''
		self.trace("tracked.save")
		now = datetimenow()
		if not self.id: # creacion
			if not self.cuser:
				self.cuser = getattr(self, '_user')
				self.cdatetime = getattr(self, '_datetime', now)
		self.muser = getattr(self, '_user')
		self.mdatetime = getattr(self, '_datetime', now)
		return super(tracked, self).save(*a, **kw)

